#include "tcpClient.h"
#include <iostream>
#include <fcntl.h>


using namespace std;


/**
 * @brief 构造函数
 * @param ip 服务器IP地址
 * @param port 服务器端口
 * @return
 */
tcpClient::tcpClient():m_clientfd(-1), m_ip(""), m_port(0)
{

}

/**
 * @brief 析构函数
 * @param ip 服务器IP地址
 * @param port 服务器端口
 * @return true 成功 false 失败
 */
// bool tcpClient::connect(const string& ip, short port)
// {
//     if(m_clientfd != -1)
//     {
//         // 已经连接，不需要再次连接
//         return true;
//     }
//     // 保存服务器IP地址和端口
//     m_ip = ip;
//     m_port = port;
//     // 创建socket
//     int sockfd = socket(AF_INET, SOCK_STREAM, 0);
//     if(sockfd == -1)
//     {
//         perror("socket");
//         return false;
//     }
//     // 设置为非阻塞
//     int flags = fcntl(sockfd, F_GETFL, 0);
//     fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
//     // 连接服务器
//     struct sockaddr_in server_addr;
//     memset(&server_addr, 0, sizeof(server_addr));
//     server_addr.sin_family = AF_INET;
//     server_addr.sin_port = htons(m_port);
//     // server_addr.sin_addr.s_addr = inet_addr(ip);
//     // gethostbyname可以操作域名、IP地址、主机名
//     struct hostent* tmp;                        
//     tmp = gethostbyname(m_ip.c_str());               
//     if(tmp == nullptr)
//     {
//         perror("gethostbyname");
//         ::close(sockfd);
//         return false;
//     }
//     memcpy(&server_addr.sin_addr, tmp->h_addr, tmp->h_length);    
//     if(::connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
//     {
//         perror("connect");
//         return false;
//     }
//     // 连接成功，保存socket
//     m_clientfd = sockfd;
//     return true;
// }

bool tcpClient::connect(const string& ip, short port)
{
    if (m_clientfd != -1) {
        return true;  // 已连接
    }

    m_ip = ip;
    m_port = port;

    // 1. 创建 socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        return false;
    }

    // 2. 设置为非阻塞
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    // 3. 解析地址
    struct sockaddr_in server_addr{};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(m_port);

    struct hostent* tmp = gethostbyname(m_ip.c_str());
    if (tmp == nullptr) {
        perror("gethostbyname");
        ::close(sockfd);
        return false;
    }
    memcpy(&server_addr.sin_addr, tmp->h_addr, tmp->h_length);

    // 4. 发起非阻塞 connect
    int ret = ::connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if (ret == 0) {
        // 立即成功（极少见）
        m_clientfd = sockfd;
        return true;
    }

    if (errno != EINPROGRESS) {
        // 真正出错
        perror("connect");
        ::close(sockfd);
        return false;
    }

    // 5. 等待连接完成（超时 3 秒）
    fd_set wfds;
    FD_ZERO(&wfds);
    FD_SET(sockfd, &wfds);

    struct timeval tv;
    tv.tv_sec  = 3;
    tv.tv_usec = 0;

    ret = select(sockfd + 1, nullptr, &wfds, nullptr, &tv);
    if (ret <= 0) {
        // 超时或出错
        fprintf(stderr, "connect timeout or error\n");
        ::close(sockfd);
        return false;
    }

    // 6. 检查 socket 错误
    int sock_err = 0;
    socklen_t len = sizeof(sock_err);
    if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &sock_err, &len) == -1 || sock_err != 0) {
        fprintf(stderr, "connect failed: %s\n", strerror(sock_err));
        ::close(sockfd);
        return false;
    }

    // 7. 连接成功
    m_clientfd = sockfd;
    return true;
}

/**
 * @brief 发送数据到服务器
 * @param msg 待发送数据(使用string兼容各种数据类型)
 * @return true 成功 false 失败
 */
bool tcpClient::send(const string& msg)
{
    if(m_clientfd == -1)
    {
        // 未连接，无法发送数据
        return false;
    }
    //  向服务器发送数据
    ssize_t sent = write(m_clientfd, msg.data(), msg.size());

    if(sent == -1)
    {
        perror("write");
        return false;
    }
    return true;
}


bool tcpClient::recv(string& msg, const size_t& maxlen)
{
    if(m_clientfd == -1)
    {
        // 未连接，无法接收数据
        return false;
    }
    // 接收服务器响应数据
    msg.clear();
    msg.resize(maxlen);
    ssize_t rev = read(m_clientfd, &msg[0], maxlen);
    if(rev == -1)
    {
        perror("read");
        msg.clear();
        return false;
    }
    else if(rev == 0)
    {
        // 服务器关闭连接
        msg.clear();
        return false;
    }
    // 收到数据，截断末尾的空字符
    msg.resize(rev);
    return true;
}

void tcpClient::close()
{
    ::close(m_clientfd);
    m_clientfd = -1;
    m_ip.clear();
    m_port = 0;
}

tcpClient::~tcpClient()
{
    ::close(m_clientfd);
}


int demo_main(int argc, char *argv[])
{
    if(argc < 3)
    {
        cerr << "用法: " << argv[0] << " <服务器地址> <端口>" << endl;
        return -1;
    }

    tcpClient client;

    if(!client.connect(argv[1], atoi(argv[2])))
    {
        cerr << "连接服务器失败" << endl;
        return -1;
    }

    string msg;
    while(true)
    {
        cout << "请输入要发送的消息(输入exit退出): ";
        getline(cin, msg);
        if(msg == "exit")
        {
            break;
        }
        if(!client.send(msg))
        {
            cerr << "发送失败" << endl;
            perror("send");
            break;
        }
        string recvmsg;
        if(!client.recv(recvmsg, 1024))
        {
            cerr << "接收失败" << endl;
            break;
        }
        cout << "服务器响应: " << recvmsg << endl;
    }
    client.close();

    return 0;
}
